package com.account.book.service.impl;

import com.account.book.common.exception.BasicInfoException;
import com.account.book.common.exception.BasicInfoStatusEnum;
import com.account.book.entity.BookMoney;
import com.account.book.enums.BookMoneyTypeEnum;
import com.account.book.enums.DataStatusEnum;
import com.account.book.enums.StatisticsSubsectionTypeEnum;
import com.account.book.mapper.BookMoneyMapper;
import com.account.book.request.StatisticsReqVo;
import com.account.book.response.StatisticsCollectMoneyListRes;
import com.account.book.response.StatisticsCollectMoneyRes;
import com.account.book.response.StatisticsMoneyCountRes;
import com.account.book.response.StatisticsMoneyRes;
import com.account.book.service.BookMoneyService;
import com.account.book.service.StatisticsService;
import com.account.book.util.TimeToolUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liang-hw
 * @className ReportServiceImpl
 * @description 图表统计
 * @date 2023/11/09 14:29:17
 */
@Service
public class StatisticsServiceImpl implements StatisticsService {
    private static final Logger logger = LoggerFactory.getLogger(StatisticsServiceImpl.class);
    @Autowired
    private BookMoneyMapper bookMoneyMapper;
    @Autowired
    private BookMoneyService bookMoneyService;
    @Autowired
    private MapperFacade mapperFacade;


    /**
     * @param @param statisticsReqVo
     * @return @return {@link StatisticsMoneyCountRes }
     * @author liang-hw
     * @description 收支总览统计
     * @date 2024/01/11 14:08:32
     */
    @Override
    public StatisticsMoneyCountRes total(StatisticsReqVo statisticsReqVo) {
        if (statisticsReqVo.getBookId() == null) {
            logger.error("查询失败，id参数未传递,bookId:", statisticsReqVo.getBookId());
            throw new BasicInfoException(BasicInfoStatusEnum.SYSTEM_ERROR.getCode(),
                    "请选择账本进行查询");
        }
        StatisticsMoneyCountRes statisticsMoneyCountRes = new StatisticsMoneyCountRes();
        //重新赋值入参不改变原入参
        StatisticsReqVo statisticsReqVoOne = mapperFacade.map(statisticsReqVo, StatisticsReqVo.class);
        conversionDate(statisticsReqVoOne);
        //查询收入
        BigDecimal selectIncome = bookMoneyMapper.getBookMoney(statisticsReqVoOne.getBookId(), statisticsReqVoOne.getStartTime(), statisticsReqVoOne.getEndTime(), BookMoneyTypeEnum.INCOME.getValue());
        //查询支出
        BigDecimal selectExpenditure = bookMoneyMapper.getBookMoney(statisticsReqVoOne.getBookId(), statisticsReqVoOne.getStartTime(), statisticsReqVoOne.getEndTime(), BookMoneyTypeEnum.DISBURSE.getValue());
        //统计数量
        Long count = bookMoneyService.count(queryWrapper(statisticsReqVo));
        statisticsMoneyCountRes.setSelectIncome(selectIncome);
        statisticsMoneyCountRes.setSelectExpenditure(selectExpenditure);
        statisticsMoneyCountRes.setBookkeepingNum(count);
        return statisticsMoneyCountRes;
    }

    /**
     * @param @param statisticsReqVo
     * @return @return {@link StatisticsMoneyRes }
     * @author liang-hw
     * @description 图表统计
     * @date 2024/01/11 15:46:37
     */
    @Override
    public StatisticsMoneyRes chartStatistics(StatisticsReqVo statisticsReqVo) {
        StatisticsMoneyRes statisticsMoneyRes = new StatisticsMoneyRes();
        String endTime = statisticsReqVo.getEndTime();
        if (statisticsReqVo.getTimeType() == 0) {
            return statisticsMoneyRes;
        }
        if (statisticsReqVo.getBookId() == null) {
            logger.error("查询失败，id参数未传递,bookId:", statisticsReqVo.getBookId());
            throw new BasicInfoException(BasicInfoStatusEnum.SYSTEM_ERROR.getCode(),
                    "请选择账本进行查询");
        }
        List<String> col = new ArrayList<>();
        List<BigDecimal> data = new ArrayList<>();
        QueryWrapper<BookMoney> queryWrapper = queryWrapper(statisticsReqVo);
        //年统计
        if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.YEAR.getValue()) {
            queryWrapper.select("CONCAT(DATE_FORMAT(book_time, '%m' ),'月') monthDate", "sum(money) moneySum");
            queryWrapper.groupBy("DATE_FORMAT(book_time,'%Y-%m')");
            queryWrapper.orderByAsc("DATE_FORMAT(book_time,'%Y-%m')");
        } else if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.MONTH.getValue()) {
            //月统计
            if (StringUtils.isNotEmpty(endTime)) {
                queryWrapper.select("DATE_FORMAT(book_time, '%Y-%m-%d' ) monthDate", "sum(money) moneySum");
            } else {
                queryWrapper.select("CONCAT(DATE_FORMAT(book_time, '%d' ),'日') monthDate", "sum(money) moneySum");
            }
            queryWrapper.groupBy("DATE_FORMAT(book_time,'%Y-%m-%d')");
            queryWrapper.orderByAsc("DATE_FORMAT(book_time,'%Y-%m-%d')");
        } else {
            //周统计
            queryWrapper.select("DATE_FORMAT(book_time, '%Y-%m-%d') monthDate", "sum(money) moneySum");
            queryWrapper.groupBy("DATE_FORMAT(book_time,'%Y-%m-%d')");
            queryWrapper.orderByAsc("DATE_FORMAT(book_time,'%Y-%m-%d')");
        }
        if (ObjectUtils.isNotEmpty(queryWrapper)) {
            //统计数量
            List<Map<String, Object>> mapList = bookMoneyMapper.selectMaps(queryWrapper);
            for (Map<String, Object> objectMap : mapList) {
                if (ObjectUtils.isNotEmpty(objectMap)) {
                    Object value = objectMap.get("monthDate");
                    if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.WEEKS.getValue()) {
                        //周
                        value = TimeToolUtil.getDateToWeek((String) value);
                    }
                    col.add((String) value);
                    value = objectMap.get("moneySum");
                    data.add((BigDecimal) value);
                }
            }
            statisticsMoneyRes.setCol(col);
            statisticsMoneyRes.setData(data);
        }
        return statisticsMoneyRes;
    }

    /**
     * @param @param statisticsReqVo
     * @return @return {@link StatisticsCollectMoneyRes }
     * @author liang-hw
     * @description 获取汇总列表
     * @date 2024/01/11 19:31:58
     */
    @Override
    public StatisticsCollectMoneyRes getCollectList(StatisticsReqVo statisticsReqVo) {
        StatisticsCollectMoneyRes statisticsCollectMoneyRes = new StatisticsCollectMoneyRes();
        List<StatisticsCollectMoneyListRes> statisticsCollectMoneyListRes = new ArrayList<>();
        String endTime = statisticsReqVo.getEndTime();
        if (statisticsReqVo.getBookId() == null) {
            logger.error("查询失败，id参数未传递,bookId:", statisticsReqVo.getBookId());
            throw new BasicInfoException(BasicInfoStatusEnum.SYSTEM_ERROR.getCode(),
                    "请选择账本进行查询");
        }
        //重新赋值入参不改变原入参
        StatisticsReqVo statisticsReqVoOne = mapperFacade.map(statisticsReqVo, StatisticsReqVo.class);
        QueryWrapper<BookMoney> queryWrapper = queryWrapper(statisticsReqVoOne);
        queryWrapper.select("sum(money) total,avg(money) average,type");
        queryWrapper.groupBy("type");
        List<Map<String, Object>> mapList = bookMoneyMapper.selectMaps(queryWrapper);
        for (Map<String, Object> objectMap : mapList) {
            if (ObjectUtils.isNotEmpty(objectMap)) {
                Object type = objectMap.get("type");
                Object total = objectMap.get("total");
                Object average = objectMap.get("average");
                //支出
                if ((Integer) type == BookMoneyTypeEnum.DISBURSE.getValue()) {
                    statisticsCollectMoneyRes.setExpenditureTotal((BigDecimal) total);
                    statisticsCollectMoneyRes.setExpenditureAverage((BigDecimal) average);
                } else {
                    statisticsCollectMoneyRes.setIncomeTotal((BigDecimal) total);
                    statisticsCollectMoneyRes.setIncomeAverage((BigDecimal) average);
                }
            }
        }
        queryWrapper = queryWrapper(statisticsReqVo);
        //总
        if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.TOTAL.getValue()) {
            queryWrapper.select("CONCAT(DATE_FORMAT(book_time, '%Y' ),'年') monthDate", "sum(money) moneySum,type");
            queryWrapper.groupBy("DATE_FORMAT(book_time,'%Y'),type");
            queryWrapper.orderByDesc("DATE_FORMAT(book_time,'%Y')");
        } else if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.YEAR.getValue()) {
            //年统计
            queryWrapper.select("CONCAT(DATE_FORMAT(book_time, '%m' ),'月') monthDate", "sum(money) moneySum,type");
            queryWrapper.groupBy("DATE_FORMAT(book_time,'%Y-%m'),type");
            queryWrapper.orderByDesc("DATE_FORMAT(book_time,'%Y-%m')");
        } else if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.MONTH.getValue()) {
            //月统计
            if (StringUtils.isNotEmpty(endTime)) {
                queryWrapper.select("DATE_FORMAT(book_time, '%Y-%m-%d' ) monthDate", "sum(money) moneySum,type");
            } else {
                queryWrapper.select("CONCAT(DATE_FORMAT(book_time, '%d' ),'日') monthDate", "sum(money) moneySum,type");
            }
            queryWrapper.groupBy("DATE_FORMAT(book_time,'%Y-%m-%d'),type");
            queryWrapper.orderByDesc("DATE_FORMAT(book_time,'%Y-%m-%d')");
        } else if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.WEEKS.getValue()) {
            //周统计
            queryWrapper.select("DATE_FORMAT(book_time, '%Y-%m-%d') monthDate", "sum(money) moneySum,type");
            queryWrapper.groupBy("DATE_FORMAT(book_time,'%Y-%m-%d'),type");
            queryWrapper.orderByDesc("DATE_FORMAT(book_time,'%Y-%m-%d')");
        }
        if (ObjectUtils.isNotEmpty(queryWrapper)) {
            Map<String, StatisticsCollectMoneyListRes> statisticsCollectMoneyListResMap = new HashMap<>();
            //统计数量
            List<Map<String, Object>> mapListOne = bookMoneyMapper.selectMaps(queryWrapper);
            for (Map<String, Object> objectMap : mapListOne) {
                Object monthDate = objectMap.get("monthDate");
                if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.WEEKS.getValue()) {
                    //周
                    monthDate = TimeToolUtil.getDateToWeek((String) monthDate);
                }
                String monthDateStr = (String) monthDate;
                StatisticsCollectMoneyListRes statisticsCollectMoneyListRe = statisticsCollectMoneyListResMap.get(monthDateStr);
                if (ObjectUtils.isEmpty(statisticsCollectMoneyListRe)) {
                    statisticsCollectMoneyListRe = new StatisticsCollectMoneyListRes();
                    statisticsCollectMoneyListRe.setStatisticsTime(monthDateStr);
                }
                if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.WEEKS.getValue()) {
                    //周
                    statisticsCollectMoneyListRe.setStatisticsOrderTime(getWeekdayIndex(monthDateStr));
                }
                Object type = objectMap.get("type");
                Object moneySum = objectMap.get("moneySum");
                //支出
                if ((Integer) type == BookMoneyTypeEnum.DISBURSE.getValue()) {
                    statisticsCollectMoneyListRe.setStatisticsExpend((BigDecimal) moneySum);
                } else {
                    statisticsCollectMoneyListRe.setStatisticsIncome((BigDecimal) moneySum);
                }
                statisticsCollectMoneyListResMap.put(monthDateStr, statisticsCollectMoneyListRe);
            }
            //结果map转list
            if (ObjectUtils.isNotEmpty(statisticsCollectMoneyListResMap)) {
                statisticsCollectMoneyListRes = statisticsCollectMoneyListResMap.entrySet().stream()
                        .map(entry -> entry.getValue())
                        .collect(Collectors.toList());
                if (statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.WEEKS.getValue()) {
                    //周
                    statisticsCollectMoneyListRes = statisticsCollectMoneyListRes.stream().sorted(Comparator.comparing(StatisticsCollectMoneyListRes::getStatisticsOrderTime)
                            .reversed()).collect(Collectors.toList());
                } else {
                    statisticsCollectMoneyListRes = statisticsCollectMoneyListRes.stream().sorted(Comparator.comparing(StatisticsCollectMoneyListRes::getStatisticsTime)
                            .reversed()).collect(Collectors.toList());
                }

            }
        }
        statisticsCollectMoneyRes.setStatisticsCollectMoneyListRes(statisticsCollectMoneyListRes);
        return statisticsCollectMoneyRes;
    }

    /**
     * @param @param statisticsReqVo
     * @return @return {@link Wrapper }<{@link BookMoney }>
     * @author liang-hw
     * @description 查询参数整理
     * @date 2024/01/11 14:45:16
     */
    private QueryWrapper<BookMoney> queryWrapper(StatisticsReqVo statisticsReqVo) {
        conversionDate(statisticsReqVo);
        QueryWrapper<BookMoney> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(null != statisticsReqVo.getBookId(), BookMoney::getBookId, statisticsReqVo.getBookId())
                .eq(BookMoney::getStatus, DataStatusEnum.ENABLE.getValue())
                .eq(null != statisticsReqVo.getType() && statisticsReqVo.getType() != -1, BookMoney::getType, statisticsReqVo.getType())
                .ge(StringUtils.isNotEmpty(statisticsReqVo.getStartTime()), BookMoney::getBookTime, statisticsReqVo.getStartTime())
                .le(StringUtils.isNotEmpty(statisticsReqVo.getEndTime()), BookMoney::getBookTime, statisticsReqVo.getEndTime());
        return queryWrapper;
    }

    /**
     * @param @param statisticsReqVo
     * @return
     * @author liang-hw
     * @description 日期转换
     * @date 2024/01/12 11:26:34
     */
    private void conversionDate(StatisticsReqVo statisticsReqVo) {
        if (statisticsReqVo.getTimeType() != null && statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.YEAR.getValue()) {
            //年统计
            String year = statisticsReqVo.getStartTime();
            statisticsReqVo.setStartTime(TimeToolUtil.getStartOfYear(year));
            statisticsReqVo.setEndTime(TimeToolUtil.getEndOfYear(year));
        } else if (statisticsReqVo.getTimeType() != null && statisticsReqVo.getTimeType() == StatisticsSubsectionTypeEnum.MONTH.getValue()) {
            if (StringUtils.isEmpty(statisticsReqVo.getEndTime())) {
                String date = statisticsReqVo.getStartTime();
                statisticsReqVo.setStartTime(TimeToolUtil.getStartOfMonth(date));
                statisticsReqVo.setEndTime(TimeToolUtil.getEndOfMonth(date));
            }
        }
    }

    private Integer getWeekdayIndex(String dayOfWeek) {
        switch (dayOfWeek) {
            case "星期一":
                return 1;
            case "星期二":
                return 2;
            case "星期三":
                return 3;
            case "星期四":
                return 4;
            case "星期五":
                return 5;
            case "星期六":
                return 6;
            default:
                return 7;
        }
    }
}
